﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace Commnications
{
    public static class BytesHelper
    {
        /// <summary>
        /// 将十六进制字符串转为字符串，eg：
        ///"48656C6C6F20776F726C64" for "Hello world"
        /// </summary>
        /// <param name="str">十六进制字符串</param>
        /// <returns></returns>
        public static string ToHexString(string str)
        {
            var bytes = Encoding.ASCII.GetBytes(str);
            return ToHexString(bytes);
        }
        /// <summary>
        /// 将十六进制数组转为字符串，eg：
        ///"48656C6C6F20776F726C64" for "Hello world"
        /// </summary>
        /// <param name="bytes">十六进制数组</param>
        /// <returns></returns>
        public static string ToHexString(byte[] bytes)
        {
            var sb = new StringBuilder();
            foreach (var t in bytes)
            {
                sb.Append(t.ToString("X02"));
            }
            return sb.ToString();  
        }
        /// <summary>
        /// 将十六进制转为字符串，eg：
        /// "Hello world" for "48656C6C6F20776F726C64"
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        public static string GetStringFromHexText(string hexString)
        {
            var bytes = new byte[hexString.Length / 2];
            for (var i = 0; i < bytes.Length; i++)
            {
                bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }
            return Encoding.ASCII.GetString(bytes); 
        }
        /// <summary>
        /// 将十六进制字符串转为数组
        /// </summary>
        /// <param name="hexString">每个字节占用2位，每两位中间不含空格</param>
        /// <param name="containSpace"></param>
        /// <returns></returns>
        public static byte[] ToHexBytes(string hexString,bool containSpace)
        {
            if (containSpace)
                hexString = hexString.Replace(" ", "");
            var bytes = new byte[hexString.Length / 2];
            for (var i = 0; i < bytes.Length; i++)
            {
                bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }
            return bytes;
        }
        /// <summary>
        /// 将十进制字符转为整形
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public static int HexCharToInt(char c)
        {
            int v = char.ToUpper(c);
            if (c >= '0' && c <= '9')
                return c - '0';
            else if (c >= 'A' && c <= 'F')
                return (c - 'A') + 10;
            return 0;
        }
        /// <summary>
        /// 将十六进制字符串解码(配置在软件外部，防止加载到内存后按预期不被转义）
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string HexStringDecode(string s)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < s.Length; i += 2)
            {
                int c1 = (HexCharToInt(s[i]) << 4);
                int c2 = (i < s.Length - 1) ? HexCharToInt(s[i + 1]) : 0;
                sb.Append((char)(c1 | (c2 & 0x0F)));
            }
            return sb.ToString();
        }
        /// <summary>
        /// 字节序转换
        /// </summary>
        /// <param name="byteOrder"></param>
        /// <param name="data"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static byte[] ByteTransfer(ByteOrder byteOrder, byte[] data, int index = 0)
        {
            byte[] buffer = new byte[4];
            switch (byteOrder)
            {
                case ByteOrder.ABCD:
                    {
                        buffer[0] = data[index + 3];
                        buffer[1] = data[index + 2];
                        buffer[2] = data[index + 1];
                        buffer[3] = data[index + 0];
                        break;
                    }
                case ByteOrder.BADC:
                    {
                        buffer[0] = data[index + 2];
                        buffer[1] = data[index + 3];
                        buffer[2] = data[index + 0];
                        buffer[3] = data[index + 1];
                        break;
                    }

                case ByteOrder.CDAB:
                    {
                        buffer[0] = data[index + 1];
                        buffer[1] = data[index + 0];
                        buffer[2] = data[index + 3];
                        buffer[3] = data[index + 2];
                        break;
                    }
                case ByteOrder.DCBA:
                    {
                        buffer[0] = data[index + 0];
                        buffer[1] = data[index + 1];
                        buffer[2] = data[index + 2];
                        buffer[3] = data[index + 3];
                        break;
                    }
            }
            return buffer;
        }
        /// <summary>
        /// word转换(2个ushort）
        /// </summary>
        /// <param name="byteOrder">转换规则规则</param>
        /// <param name="data">数据</param>
        /// <param name="index">数组索引，默认0</param>
        /// <returns></returns>
        public static byte[] WordTransfer(ByteOrder byteOrder, ushort[] data, int index=0)
        {
            byte a = (byte)((data[index] & 0xFF00) >> 8); 
            byte b = (byte)(data[index] & 0x00FF);
            byte c = (byte)((data[index+1] & 0xFF00) >> 8); 
            byte d = (byte)(data[index+1] & 0x00FF);
            byte[] buffer = null;

            switch (byteOrder)
            {
                case ByteOrder.ABCD:
                default:
                    buffer = new byte[] { a, b, c, d };
                    break;
                case ByteOrder.DCBA:
                    buffer = new byte[] { d, c, b, a };
                    break;
                case ByteOrder.BADC:
                    buffer = new byte[] { b, a, d, c };
                    break;
                case ByteOrder.CDAB:
                    buffer = new byte[] { c, d, a, b };
                    break;
            }

            return buffer;
        }

        #region serialize&deserialize data begin
        /// <summary>
        /// 将结构体转为字节数组
        /// </summary>
        /// <param name="buffer">数组</param>
        /// <param name="data">结构体</param>
        /// <param name="offset">数组起始地址</param>
        /// <param name="len">数组长度,默认-1(则自动使用结构体长度)</param>
        public static void PackPayload(byte[] buffer, object data, ref int offset, int len = -1)
        {
            var bytes = StructToBytes(data, len);
            Array.Copy(bytes, 0, buffer, offset, bytes.Length);
            offset += bytes.Length;
        }
        /// <summary>
        /// 将字节数组反序列化为结构体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="buffer">字节数组</param>
        /// <param name="offset">字节数组数据起始地址</param>
        /// <returns></returns>
        public static T UnpackPayload<T>(this byte[] buffer, ref int offset)
        {
            try
            {
                var size = Marshal.SizeOf(typeof(T));
                byte[] bufferObj = new byte[size];
                Array.Copy(buffer, offset, bufferObj, 0, size);
                T data = (T)BytesToStruct(bufferObj, typeof(T));
                offset += size;
                return data;
            }
            catch (Exception)
            {
                return default(T);
            }
        }
        /// <summary>
        /// 结构体转字节数组
        /// </summary>
        /// <param name="structObj">要转换的结构体</param>
        /// <returns>转换后的byte数组</returns>
        public static byte[] StructToBytes(object structObj, int len = -1)
        {
            int size = 0;
            return StructToBytes(structObj, ref size, len);
        }
        public static byte[] StructToBytes(object structObj, ref int with, int len = -1)
        {
            int size = Marshal.SizeOf(structObj);
            if (len >= 0)
                size = len;
            byte[] bytes = new byte[size];
            with = size;
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            try
            {
                Marshal.StructureToPtr(structObj, structPtr, false);
                Marshal.Copy(structPtr, bytes, 0, size);
            }
            finally
            {
                Marshal.FreeHGlobal(structPtr);
            }
            return bytes;
        }

        public static int MarshalSize(Type type)
        {
            return Marshal.SizeOf(type);
        }
        public static string GetString(this byte[] buffer, Encoding encoding, int offset = 0, int len = -1)
        {
            if (len <= 0)
            {
                len = buffer.Length;
            }
            return encoding.GetString(buffer, offset, len);
        }
        /// <summary>
        /// 按指定编码获取字符串
        /// </summary>
        /// <param name="buffer">数组</param>
        /// <param name="offset">偏移起始地址</param>
        /// <param name="encodingName">编码名称</param>
        /// <returns></returns>
        public static string GetString(this byte[] buffer, int offset = 0, int len = -1, string encodingName = "ascii")
        {
            return GetString(buffer, Encoding.GetEncoding(encodingName), offset, len);
        }
        /// <summary>
        /// 将字节数组转结构体
        /// </summary>
        /// <param name="bytes">字节数组</param>
        /// <param name="type">结构体类型</param>
        /// <returns>转换后的结构体</returns>
        public static object BytesToStruct(this byte[] bytes, Type type, int offset = 0)
        {
            int size = Marshal.SizeOf(type);
            if (size > bytes.Length)
            {
                return null;
            }
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            try
            {
                Marshal.Copy(bytes, offset, structPtr, size);
                object obj = Marshal.PtrToStructure(structPtr, type);
                return obj;
            }
            catch (Exception)
            {
            }
            finally
            {
                Marshal.FreeHGlobal(structPtr);
            }
            return null;
        }
        /// <summary>
        /// 将字节数组转结构体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="bytes">字节数组</param>
        /// <returns></returns>
        public static T BytesToStruct<T>(this byte[] bytes, int offset = 0)
        {
            var type = typeof(T);
            var obj = default(T);
            try
            {
                obj = (T)BytesToStruct(bytes, type, offset);
            }
            catch (Exception)
            {
            }
            return obj;
        }
        /// <summary>
        /// 将字节结构体转为字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public static string BytesToString(this byte[] bytes, int size, int offset = 0)
        {
            if (size > bytes.Length)
            {
                return null;
            }
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            string obj = null;
            try
            {
                Marshal.Copy(bytes, offset, structPtr, size);
                obj = Marshal.PtrToStringAnsi(structPtr, size);
            }
            catch (Exception)
            {
            }
            finally
            {
                Marshal.FreeHGlobal(structPtr);
            }
            return obj;
        }
        #endregion serialize&deserialize data end
    }
    /// <summary>
    /// 4字节编码类型
    /// </summary>
    public enum ByteOrder
    {
        /// <summary>
        /// 按照顺序排序
        /// </summary>
        ABCD = 0,

        /// <summary>
        /// 按照单字反转
        /// </summary>
        BADC = 1,

        /// <summary>
        /// 按照双字反转
        /// </summary>
        CDAB = 2,

        /// <summary>
        /// 按照倒序排序
        /// </summary>
        DCBA = 3,
    }
}
